home *** CD-ROM | disk | FTP | other *** search
- /* Higher level user subroutines built on top of the socket primitives
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mods by PA0GRI
- */
- #include "global.h"
- #include <stdarg.h>
- #include "mbuf.h"
- #include "proc.h"
- #include "socket.h"
- #ifdef LZW
- #include "lzw.h"
- #else
- #include "usock.h"
- #endif
- #include "session.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: sockuser.c,v 1.33 1997/09/07 00:31:16 root Exp root $";
- #endif
-
-
- extern void backEmUp (int len);
- int sockblock (int s, int value);
- extern const char hitEnter[];
-
- #ifdef FIFOSERVER
- extern int FIFOout;
- #endif
-
-
- /* Higher-level receive routine, intended for connection-oriented sockets.
- * Can be used with datagram sockets, although the sender id is lost.
- */
- int
- recv (s, buf, len, flags)
- int s; /* Socket index */
- char *buf; /* User buffer */
- int len; /* Max length to receive */
- int flags; /* Unused; will eventually select oob data, etc */
- {
- struct mbuf *bp;
- int cnt;
-
- if (len == 0)
- return 0; /* Otherwise would be interp as "all" */
-
- cnt = recv_mbuf (s, &bp, flags, NULLCHAR, (int *) NULL);
- if (cnt > 0) {
- cnt = min (cnt, len);
- (void) pullup (&bp, (unsigned char *) buf, (int16) cnt);
- free_p (bp);
- }
- return cnt;
- }
-
-
-
- /* Higher level receive routine, intended for datagram sockets. Can also
- * be used for connection-oriented sockets, although from and fromlen are
- * ignored.
- */
- int
- recvfrom (s, buf, len, flags, from, fromlen)
- int s; /* Socket index */
- char *buf; /* User buffer */
- int len; /* Maximum length */
- int flags; /* Unused; will eventually select oob data, etc */
- char *from; /* Source address, only for datagrams */
- int *fromlen; /* Length of source address */
- {
- struct mbuf *bp;
- register int cnt;
-
- cnt = recv_mbuf (s, &bp, flags, from, fromlen);
- if (cnt > 0) {
- cnt = min (cnt, len);
- (void) pullup (&bp, (unsigned char *) buf, (int16) cnt);
- free_p (bp);
- }
- return cnt;
- }
-
-
-
- /* High level send routine */
- int
- send (s, buf, len, flags)
- int s; /* Socket index */
- char *buf; /* User buffer */
- int len; /* Length of buffer */
- int flags; /* Unused; will eventually select oob data, etc */
- {
- register struct mbuf *bp;
- char sock[MAXSOCKSIZE];
- int i = MAXSOCKSIZE;
-
- if (getpeername (s, sock, &i) == -1)
- return -1;
- bp = qdata ((unsigned char *) buf, (int16) len);
- return send_mbuf (s, bp, flags, sock, i);
- }
-
-
-
- /* High level send routine, intended for datagram sockets. Can be used on
- * connection-oriented sockets, but "to" and "tolen" are ignored.
- */
- int
- sendto (s, buf, len, flags, to, tolen)
- int s; /* Socket index */
- char *buf; /* User buffer */
- int len; /* Length of buffer */
- int flags; /* Unused; will eventually select oob data, etc */
- char *to; /* Destination, only for datagrams */
- int tolen; /* Length of destination */
- {
- register struct mbuf *bp;
-
- bp = qdata ((unsigned char *) buf, (int16) len);
- return send_mbuf (s, bp, flags, to, tolen);
- }
-
-
-
- /* Receive a newline-terminated line from a non-blocking input socket,
- * returning # chars read. The end-of-line sequence is recognized and
- * translated into a single '\n'.
- */
- int
- nb_recvline (s, buf, len)
- int s; /* Socket index */
- unsigned char *buf; /* User buffer */
- unsigned len; /* Length of buffer */
- {
- int c;
- int cnt = 0;
-
- while (len-- > 1) {
- while ((c = recvchar (s)) == EOF) {
- if (errno != EWOULDBLOCK)
- return -1;
-
- if (kpause (500) == -1)
- return -1;
- }
- if (buf != (unsigned char *) 0)
- *buf++ = uchar(c);
- cnt++;
- if (uchar (c) == '\n')
- break;
- }
- if (buf != (unsigned char *) 0)
- *buf = '\0';
- return cnt;
- }
-
-
-
- /* Receive a newline-terminated line from a socket, returning # chars read.
- * The end-of-line sequence is recognized and translated into a single '\n'.
- */
- int
- recvline (s, buf, len)
- int s; /* Socket index */
- unsigned char *buf; /* User buffer */
- unsigned len; /* Length of buffer */
- {
- int c;
- int cnt = 0;
-
- while (len-- > 1) {
- if ((c = recvchar (s)) == EOF) {
- cnt = -1;
- break;
- }
- if (buf != (unsigned char *) 0)
- *buf++ = uchar(c);
- cnt++;
- if (uchar (c) == '\n')
- break;
- }
- if (buf != (unsigned char *) 0)
- *buf = '\0';
- return cnt;
- }
-
-
-
- /* Do printf on a user socket */
- int
- usprintf (int s, const char *fmt,...)
- {
- va_list args;
- int len;
-
- va_start (args, fmt); /*lint !e718 !e746 */
- len = usvprintf (s, fmt, args);
- va_end (args);
- return len;
- }
-
-
- /* Printf on standard output socket */
- int
- tprintf (const char *fmt,...)
- {
- va_list args;
- int len;
-
- va_start (args, fmt);
- len = usvprintf (Curproc->output, fmt, args);
- va_end (args);
- return len;
- }
-
-
- #if defined(SCREENSAVER) && defined(UNIX)
- int16 intrace = 0;
- #endif
-
- #ifdef TRACE
- extern int tracesock;
-
-
- /* Print on Tracesession stdout socket */
- void
- traceprintf (FILE * fp, const char *fmt,...)
- {
- va_list args;
-
- #if defined(SCREENSAVER) && defined(UNIX)
- intrace = 1;
- #endif
- va_start (args, fmt);
- if (fp == stdout) {
- (void) usvprintf (tracesock, fmt, args);
- (void) usflush (tracesock);
- } else
- (void) vfprintf (fp, fmt, args);
- va_end (args);
- #if defined(SCREENSAVER) && defined(UNIX)
- intrace = 0;
- #endif
- }
-
- #endif
-
-
- #ifdef UNIX
- extern void sm_status (int pos, char *str);
- #endif
-
-
- /* New style - use session manager switch's status entry point */
- int
- tcmdprintf (const char *fmt,...)
- {
- va_list args;
- char *buf;
- int len;
-
- buf = mallocw (SOBUF);
- va_start (args, fmt);
- if ((len = VSPRINTF ((buf, fmt, args))) >= SOBUF) {
- log (-1, "tcmdprintf() buffer overflow");
- where_outta_here (2, "tcmdprintf");
- }
- va_end (args);
- #ifdef UNIX
- sm_status (0, buf);
- #else
- usputs (Command->proc->output, buf);
- #endif
- free (buf);
- return len;
- }
-
-
-
- #ifdef UNIX
- /* Print on Command stdout socket or a file */
- int
- tfprintf (FILE * fp, const char *fmt,...)
- {
- va_list args;
- int len;
-
- va_start (args, fmt);
- if (fp == stdout)
- len = usvprintf (Command->output, fmt, args);
- else
- len = vfprintf (fp, fmt, args);
- va_end (args);
- return len;
- }
-
- #endif
-
-
-
-
- /* The guts of printf, uses variable arg version of sprintf */
- int
- usvprintf (int s, const char *fmt, va_list args)
- {
- int len;
- char *buf;
-
- if (strchr (fmt, '%') == NULLCHAR) {
- /* Common case optimization: no args, so we don't
- * need vsprintf()
- */
- buf = strdup (fmt);
- len = (int) strlen (fmt);
- } else {
- /* Use a default value that is hopefully longer than the
- * biggest output string we'll ever print (!)
- */
- buf = mallocw (SOBUF);
- /* Start of mod by N4YYH */
- if ((len = VSPRINTF ((buf, fmt, args))) >= SOBUF) {
- /* It's too late to be sorry. He's dead, Jim. */
- log (s, "usvprintf() has exceeded the size of it's buffer. Restarting NOS.");
- where_outta_here (2, "usvprintf");
- }
- /* End of mod by N4YYH */
- }
- if (usputs (s, buf) == EOF)
- len = -1;
- free (buf);
- return len;
- }
-
-
- /* Buffered putchar to a socket */
- int
- usputc (int s, const unsigned char c)
- {
- struct usock *up;
- register struct mbuf *bp;
- unsigned char *cp;
- /*lint -esym(550,len) */
- int newline, len;
-
- if (nullsocket (s)) {
- errno = EBADF;
- return -1;
- }
- up = itop (s);
- if (c == '\n' && (up->flag & SOCK_ASCII)) {
- newline = 1;
- len = (int) strlen (up->eol);
- } else {
- newline = 0;
- len = 1;
- }
- #ifndef LZW
- /* Make sure there's room in the current buffer, if any */
- if ((bp = up->obuf) != NULLBUF) {
- if ((bp->cnt >= bp->size - len) && usflush (s) == -1)
- return EOF;
- }
- #endif
- if (up->obuf == NULLBUF) /* Allocate a buffer of appropriate size */
- up->obuf = ambufw (BUFSIZ);
-
- /* Note: the buffer must be larger than the end-of-line sequence! */
- bp = up->obuf;
- cp = &bp->data[bp->cnt];
- if (newline) {
- /* Translate into appropriate end-of-line sequence */
- #ifdef LZW
- for (cp = (unsigned char *) up->eol; *cp != '\0'; cp++)
- if (up->zout == NULLLZW)
- bp->data[bp->cnt++] = *cp;
- else
- lzwencode (s, (char) *cp);
- #else
- strncpy (cp, up->eol, len);
- #endif
- } else {
- #ifdef LZW
- if (up->zout == NULLLZW)
- bp->data[bp->cnt++] = c;
- else
- lzwencode (s, (char) c);
- }
- #else
- *cp = c;
- }
- bp->cnt += len;
- #endif
- /* Flush if necessary and leave enough room for a coming eol */
- if ((c == up->flush && up->flush != -1) || bp->cnt >= bp->size - 9)
- if (usflush (s) == -1)
- return -1;
-
- #ifdef LOOKSESSION
- if (up->look) /* Some one is looking at us ! */
- usputc (up->look->output, c);
- #endif
- return (int) uchar (c);
- }
- /*lint +esym(550,len) */
-
-
-
- /* Put a character to standard output socket */
- int
- tputc (unsigned char c)
- {
- return usputc (Curproc->output, c);
- }
-
-
-
- #ifndef oldusputs
- /* Buffered puts to a socket */
- int
- usputs (int s, const char *buf)
- {
- register struct usock *up;
- register struct mbuf *bp;
- unsigned char *cp, *wp;
- int16 len, clen;
- int doflush;
- int eol_len = 0;
- int16 flushpt;
- int ascii;
- #ifdef LOOKSESSION
- const char *oldbuf;
- #endif
-
- #ifdef FIFOSERVER
- if (s < SOCKBASE && s == FIFOout) {
- write (s, buf, strlen (buf));
- return 0;
- }
- #endif
- if (nullsocket (s)) {
- errno = EBADF;
- return EOF;
- }
- up = itop (s);
- #ifdef LOOKSESSION
- oldbuf = buf;
- #endif
- #ifdef LZW
- if (up->zout != NULLLZW) {
- while (*buf != '\0')
- if (usputc (s, uchar(*buf++)) == EOF)
- return EOF;
- return 0;
- }
- #endif
- ascii = up->flag & SOCK_ASCII;
- if (ascii)
- eol_len = (int) strlen (up->eol);
- doflush = (up->flush != -1) && (strchr (buf, up->flush) != NULLCHAR);
- len = (int16) strlen (buf);
-
- while (len != 0) {
- if (up->obuf == NULLBUF) {
- /* Allocate a buffer of appropriate size */
- clen = BUFSIZ;
- up->obuf = ambufw (clen);
- }
- /* Note: the buffer must be larger than the end-of-line sequence! */
- bp = up->obuf;
- wp = &bp->data[bp->cnt];
- #ifdef TNOS_68K
- if (ascii && (cp = strchr (buf, '\l')) != (unsigned char *) 0) {
- #else
- if (ascii && (cp = (unsigned char *) strpbrk (buf, "\n")) != (unsigned char *) 0) {
- #endif
- /* Copy up to, but not including, newline */
- clen = (int16) ((const char *) cp - buf);
- } else /* Copy whole thing */
- clen = len;
-
- /* ...but no more than the room available */
- clen = min (clen, bp->size - bp->cnt);
- if (clen != 0) {
- memcpy (wp, buf, (size_t) clen);
- wp += clen;
- bp->cnt += clen;
- buf += clen;
- len -= clen;
- }
- /* Set flush threshold to allow for eol, if enabled */
- if (ascii)
- flushpt = (int16) (bp->size - eol_len);
- else
- flushpt = bp->size;
-
- if (ascii && (*buf == '\n') && bp->cnt < flushpt) {
- /* Add appropriate end-of-line sequence */
- strncpy ((char *) wp, up->eol, (size_t) eol_len);
- wp += eol_len;
- bp->cnt += (int16) eol_len;
- buf++; /* Skip newline in buffer */
- len--;
- }
- if (bp->cnt >= flushpt) {
- /* Buffer full, flush and get another */
- if (usflush (s) == -1)
- return EOF;
- }
- }
- if (doflush && usflush (s) == -1)
- return EOF;
-
- #ifdef LOOKSESSION
- if (up->look) /* someone is looking at us ! */
- usputs (up->look->output, oldbuf);
- #endif
- return 0;
- }
-
- #else
-
-
- int
- usputs (int s, register const char *x)
- {
- while (*x != '\0')
- if (usputc (s, *x++) == EOF)
- return EOF;
- return 0;
- }
-
- #endif
-
-
-
-
- #ifdef FBBFWD
- int
- usputbuf (int s, register const unsigned char *x, int len)
- {
- while (--len >= 0)
- if (usputc (s, *x++) == EOF)
- return EOF;
- return 0;
- }
-
- #endif
-
-
-
- /* Put a string to standard output socket */
- int
- tputs (const char *s)
- {
- return usputs (Curproc->output, s);
- }
-
-
-
- /* Read a raw character from a socket with stream buffering. */
- int
- rrecvchar (s)
- int s; /* Socket index */
- {
- register struct usock *up;
- register int c;
-
- if (nullsocket (s))
- return EOF;
- up = itop (s);
- #ifdef LZW
- if (up->zin != NULLLZW)
- if ((c = lzwdecode (up)) != -1)
- return c;
- #endif
- #if 1
- if (up->insertbuf) {
- c = *up->insertptr++;
- if (!*up->insertptr) {
- free (up->insertbuf);
- up->insertbuf = NULLCHAR;
- }
- return c;
- }
- #endif
- /* Replenish if necessary */
- if (up->ibuf == NULLBUF && recv_mbuf (s, &up->ibuf, 0, NULLCHAR, 0) <= 0)
- return EOF;
-
- #ifdef LZW
- if (up->zin != NULLLZW)
- if ((c = lzwdecode (up)) != -1)
- return c;
- else
- return rrecvchar (s); /* needs replenish */
- #endif
- c = PULLCHAR (&up->ibuf); /* returns -1 if eof */
-
- return (c == -1 ? EOF : c);
- }
-
-
-
- /* This function recognizes the end-of-line sequence for the stream
- * and translates it into a single '\n'.
- */
- int
- recvchar (s)
- int s; /* Socket index */
- {
- int c;
- register struct usock *up;
- int inserted;
-
- if (nullsocket (s))
- return EOF;
-
- up = itop (s);
- inserted = (up->insertbuf) ? 1 : 0;
- c = rrecvchar (s);
-
- if (c != up->eol[0] || !(up->flag & SOCK_ASCII)) {
- #ifdef LOOKSESSION
- if (Current != Command && up->look && !inserted && c != EOF)
- usputc (up->look->output, uchar(c));
- #endif
- return c;
- }
- /* This is the first char of a eol sequence. If the eol sequence is
- * more than one char long, eat the next character in the input stream.
- */
- if (up->eol[1] != '\0')
- (void) rrecvchar (s);
-
- #ifdef LOOKSESSION
- if (up->look && !inserted) {
- usputc (up->look->output, '\n');
- /* In the case 'looking' is done from bbs connection,
- * flush it here... */
- usflush (up->look->output);
- }
- #endif
- return '\n';
- }
-
-
-
- /* Flush output on a socket stream */
- int
- usflush (int s)
- {
- register struct usock *up;
- struct mbuf *bp;
-
- if (nullsocket (s))
- return -1;
-
- up = itop (s);
- if (up->obuf != NULLBUF) {
- #ifdef LZW
- if (up->zout != NULLLZW)
- lzwflush (up);
- #endif
- bp = up->obuf;
- up->obuf = NULLBUF;
- return send_mbuf (s, bp, 0, NULLCHAR, 0);
- }
- #ifdef LOOKSESSION
- if (up->look) /* Some one is looking at us, flush them as well */
- usflush (up->look->output);
- #endif
- return 0;
- }
-
-
-
- /* Flush output socket */
- void
- tflush ()
- {
- usflush (Current->output);
- }
-
-
-
- /* Print prompt and read one character */
- int
- keywait (prompt, flush)
- const char *prompt; /* Optional prompt */
- int flush; /* Flush queued input? */
- {
- int c;
- const char *pm;
- int block = SOCK_BLOCK;
-
- if (prompt == NULLCHAR)
- block = sockblock (Curproc->input, SOCK_BLOCK);
- if (flush && socklen (Curproc->input, 1) != 0)
- (void) recv_mbuf (Curproc->input, NULLBUFP, 0, NULLCHAR, 0); /* flush */
- pm = (prompt == NULLCHAR) ? hitEnter : prompt;
- tputs (pm);
- tflush ();
- c = recvchar (Curproc->input);
- backEmUp ((int) strlen (pm));
- if (prompt == NULLCHAR)
- (void) sockblock (Curproc->input, block);
- return (int) c;
- }
-
-
-
- /* Set the end-of-line sequence on a socket */
- int
- seteol (int s, const char *seq)
- {
- register struct usock *up;
-
- /* Do *NOT* use nullsocket() here, since this MAY
- be being called while the socket is being
- constructed, and will BE null at the time. */
- if ((up = itop (s)) == NULLUSOCK)
- return -1;
-
- if (seq != NULLCHAR)
- strncpy (up->eol, seq, sizeof (up->eol));
- else
- *up->eol = '\0';
- return 0;
- }
-
-
-
- /* Enable/disable eol translation, return previous state */
- int
- sockmode (int s, int mode)
- {
- struct usock *up;
- int prev;
-
- /* Do *NOT* use nullsocket() here, since this is
- sometimes called while the socket is being
- constructed, and may BE null at the time. */
- if ((up = itop (s)) == NULLUSOCK)
- return -1;
- usflush (s);
- prev = up->flag;
- switch (mode) {
- case SOCK_BINARY:
- case SOCK_ASCII:
- up->flag = mode;
- break;
- default:
- break;
- }
- return prev;
- }
-
-
-
- /* Specify the character to trigger automatic output buffer
- * flushing, or -1 to disable it. Return the previous setting.
- */
- int
- setflush (int s, int c)
- {
- register struct usock *up;
- int old;
-
- if (nullsocket (s))
- return -1;
-
- up = itop (s);
- old = up->flush;
- up->flush = c;
- return old;
- }
-
-
-
- /* Set the block mode on a socket - WG7J.
- * Primarily used on convers.c to prevent backlog of data and
- * usprintf() calls blocking because of it...
- * returns previous mode
- */
- int
- sockblock (int s, int value)
- {
- register struct usock *up;
- int oldval;
-
- if (nullsocket (s)) {
- errno = EBADF;
- return -1;
- }
- up = itop (s);
- oldval = up->noblock;
- up->noblock = (char) value;
- return oldval;
- }
-
-
-
- int
- getblock (int s)
- {
- register struct usock *up;
-
- if (nullsocket (s)) {
- errno = EBADF;
- return -1;
- }
- up = itop (s);
- return up->noblock;
- }
-
-
-
- int
- nullusock (struct usock *up)
- {
- if (up == NULLUSOCK || !up->cb.p) {
- errno = ENOTCONN;
- return 1;
- }
- return 0;
- }
-
-
- int
- nullsocket (int s)
- {
- return nullusock (itop (s));
- }
-